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_composite_construct.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/data_descriptor.h"
19 #include "source/fuzz/fuzzer_util.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "test/fuzz/fuzz_test_util.h"
22
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26
TEST(TransformationCompositeConstructTest,ConstructArrays)27 TEST(TransformationCompositeConstructTest, ConstructArrays) {
28 std::string shader = R"(
29 OpCapability Shader
30 %1 = OpExtInstImport "GLSL.std.450"
31 OpMemoryModel Logical GLSL450
32 OpEntryPoint Fragment %4 "main"
33 OpExecutionMode %4 OriginUpperLeft
34 OpSource ESSL 310
35 OpName %4 "main"
36 OpName %11 "floats"
37 OpName %22 "x"
38 OpName %39 "vecs"
39 OpName %49 "bools"
40 OpName %60 "many_uvec3s"
41 OpDecorate %60 RelaxedPrecision
42 %2 = OpTypeVoid
43 %3 = OpTypeFunction %2
44 %6 = OpTypeFloat 32
45 %7 = OpTypeInt 32 0
46 %8 = OpConstant %7 2
47 %9 = OpTypeArray %6 %8
48 %10 = OpTypePointer Function %9
49 %12 = OpTypeInt 32 1
50 %13 = OpConstant %12 0
51 %14 = OpConstant %6 1
52 %15 = OpTypePointer Function %6
53 %17 = OpConstant %12 1
54 %18 = OpConstant %6 2
55 %20 = OpTypeVector %6 2
56 %21 = OpTypePointer Function %20
57 %32 = OpTypeBool
58 %36 = OpConstant %7 3
59 %37 = OpTypeArray %20 %36
60 %38 = OpTypePointer Private %37
61 %39 = OpVariable %38 Private
62 %40 = OpConstant %6 3
63 %41 = OpConstantComposite %20 %40 %40
64 %42 = OpTypePointer Private %20
65 %44 = OpConstant %12 2
66 %47 = OpTypeArray %32 %36
67 %48 = OpTypePointer Function %47
68 %50 = OpConstantTrue %32
69 %51 = OpTypePointer Function %32
70 %56 = OpTypeVector %7 3
71 %57 = OpTypeArray %56 %8
72 %58 = OpTypeArray %57 %8
73 %59 = OpTypePointer Function %58
74 %61 = OpConstant %7 4
75 %62 = OpConstantComposite %56 %61 %61 %61
76 %63 = OpTypePointer Function %56
77 %65 = OpConstant %7 5
78 %66 = OpConstantComposite %56 %65 %65 %65
79 %67 = OpConstant %7 6
80 %68 = OpConstantComposite %56 %67 %67 %67
81 %69 = OpConstantComposite %57 %66 %68
82 %100 = OpUndef %57
83 %70 = OpTypePointer Function %57
84 %4 = OpFunction %2 None %3
85 %5 = OpLabel
86 %11 = OpVariable %10 Function
87 %22 = OpVariable %21 Function
88 %49 = OpVariable %48 Function
89 %60 = OpVariable %59 Function
90 %16 = OpAccessChain %15 %11 %13
91 OpStore %16 %14
92 %19 = OpAccessChain %15 %11 %17
93 OpStore %19 %18
94 %23 = OpAccessChain %15 %11 %13
95 %24 = OpLoad %6 %23
96 %25 = OpAccessChain %15 %11 %17
97 %26 = OpLoad %6 %25
98 %27 = OpCompositeConstruct %20 %24 %26
99 OpStore %22 %27
100 %28 = OpAccessChain %15 %11 %13
101 %29 = OpLoad %6 %28
102 %30 = OpAccessChain %15 %11 %17
103 %31 = OpLoad %6 %30
104 %33 = OpFOrdGreaterThan %32 %29 %31
105 OpSelectionMerge %35 None
106 OpBranchConditional %33 %34 %35
107 %34 = OpLabel
108 %43 = OpAccessChain %42 %39 %17
109 OpStore %43 %41
110 %45 = OpLoad %20 %22
111 %46 = OpAccessChain %42 %39 %44
112 OpStore %46 %45
113 OpBranch %35
114 %35 = OpLabel
115 %52 = OpAccessChain %51 %49 %13
116 OpStore %52 %50
117 %53 = OpAccessChain %51 %49 %13
118 %54 = OpLoad %32 %53
119 %55 = OpAccessChain %51 %49 %17
120 OpStore %55 %54
121 %64 = OpAccessChain %63 %60 %13 %13
122 OpStore %64 %62
123 %71 = OpAccessChain %70 %60 %17
124 OpStore %71 %69
125 OpReturn
126 OpFunctionEnd
127 )";
128
129 const auto env = SPV_ENV_UNIVERSAL_1_3;
130 const auto consumer = nullptr;
131 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
132 spvtools::ValidatorOptions validator_options;
133 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
134 kConsoleMessageConsumer));
135 TransformationContext transformation_context(
136 MakeUnique<FactManager>(context.get()), validator_options);
137 // Make a vec2[3]
138 TransformationCompositeConstruct make_vec2_array_length_3(
139 37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
140 200);
141 // Bad: there are too many components
142 TransformationCompositeConstruct make_vec2_array_length_3_bad(
143 37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
144 200);
145 ASSERT_TRUE(make_vec2_array_length_3.IsApplicable(context.get(),
146 transformation_context));
147 ASSERT_FALSE(make_vec2_array_length_3_bad.IsApplicable(
148 context.get(), transformation_context));
149 ApplyAndCheckFreshIds(make_vec2_array_length_3, context.get(),
150 &transformation_context);
151 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
152 kConsoleMessageConsumer));
153 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
154 MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0})));
155 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
156 MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1})));
157 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
158 MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2})));
159
160 // Make a float[2]
161 TransformationCompositeConstruct make_float_array_length_2(
162 9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
163 // Bad: %41 does not have type float
164 TransformationCompositeConstruct make_float_array_length_2_bad(
165 9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
166 ASSERT_TRUE(make_float_array_length_2.IsApplicable(context.get(),
167 transformation_context));
168 ASSERT_FALSE(make_float_array_length_2_bad.IsApplicable(
169 context.get(), transformation_context));
170 ApplyAndCheckFreshIds(make_float_array_length_2, context.get(),
171 &transformation_context);
172 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
173 kConsoleMessageConsumer));
174 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
175 MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0})));
176 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
177 MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1})));
178
179 // Make a bool[3]
180 TransformationCompositeConstruct make_bool_array_length_3(
181 47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
182 202);
183 // Bad: %54 is not available at the desired program point.
184 TransformationCompositeConstruct make_bool_array_length_3_bad(
185 47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
186 202);
187 ASSERT_TRUE(make_bool_array_length_3.IsApplicable(context.get(),
188 transformation_context));
189 ASSERT_FALSE(make_bool_array_length_3_bad.IsApplicable(
190 context.get(), transformation_context));
191 ApplyAndCheckFreshIds(make_bool_array_length_3, context.get(),
192 &transformation_context);
193 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
194 kConsoleMessageConsumer));
195 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
196 MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0})));
197 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
198 MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1})));
199 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
200 MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2})));
201
202 // make a uvec3[2][2]
203 TransformationCompositeConstruct make_uvec3_array_length_2_2(
204 58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203);
205 // Bad: Skip count 100 is too large.
206 TransformationCompositeConstruct make_uvec3_array_length_2_2_bad(
207 58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203);
208 ASSERT_TRUE(make_uvec3_array_length_2_2.IsApplicable(context.get(),
209 transformation_context));
210 ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(
211 context.get(), transformation_context));
212 ApplyAndCheckFreshIds(make_uvec3_array_length_2_2, context.get(),
213 &transformation_context);
214 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
215 kConsoleMessageConsumer));
216 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
217 MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0})));
218 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
219 MakeDataDescriptor(100, {}), MakeDataDescriptor(203, {1})));
220
221 std::string after_transformation = R"(
222 OpCapability Shader
223 %1 = OpExtInstImport "GLSL.std.450"
224 OpMemoryModel Logical GLSL450
225 OpEntryPoint Fragment %4 "main"
226 OpExecutionMode %4 OriginUpperLeft
227 OpSource ESSL 310
228 OpName %4 "main"
229 OpName %11 "floats"
230 OpName %22 "x"
231 OpName %39 "vecs"
232 OpName %49 "bools"
233 OpName %60 "many_uvec3s"
234 OpDecorate %60 RelaxedPrecision
235 %2 = OpTypeVoid
236 %3 = OpTypeFunction %2
237 %6 = OpTypeFloat 32
238 %7 = OpTypeInt 32 0
239 %8 = OpConstant %7 2
240 %9 = OpTypeArray %6 %8
241 %10 = OpTypePointer Function %9
242 %12 = OpTypeInt 32 1
243 %13 = OpConstant %12 0
244 %14 = OpConstant %6 1
245 %15 = OpTypePointer Function %6
246 %17 = OpConstant %12 1
247 %18 = OpConstant %6 2
248 %20 = OpTypeVector %6 2
249 %21 = OpTypePointer Function %20
250 %32 = OpTypeBool
251 %36 = OpConstant %7 3
252 %37 = OpTypeArray %20 %36
253 %38 = OpTypePointer Private %37
254 %39 = OpVariable %38 Private
255 %40 = OpConstant %6 3
256 %41 = OpConstantComposite %20 %40 %40
257 %42 = OpTypePointer Private %20
258 %44 = OpConstant %12 2
259 %47 = OpTypeArray %32 %36
260 %48 = OpTypePointer Function %47
261 %50 = OpConstantTrue %32
262 %51 = OpTypePointer Function %32
263 %56 = OpTypeVector %7 3
264 %57 = OpTypeArray %56 %8
265 %58 = OpTypeArray %57 %8
266 %59 = OpTypePointer Function %58
267 %61 = OpConstant %7 4
268 %62 = OpConstantComposite %56 %61 %61 %61
269 %63 = OpTypePointer Function %56
270 %65 = OpConstant %7 5
271 %66 = OpConstantComposite %56 %65 %65 %65
272 %67 = OpConstant %7 6
273 %68 = OpConstantComposite %56 %67 %67 %67
274 %69 = OpConstantComposite %57 %66 %68
275 %100 = OpUndef %57
276 %70 = OpTypePointer Function %57
277 %4 = OpFunction %2 None %3
278 %5 = OpLabel
279 %11 = OpVariable %10 Function
280 %22 = OpVariable %21 Function
281 %49 = OpVariable %48 Function
282 %60 = OpVariable %59 Function
283 %16 = OpAccessChain %15 %11 %13
284 OpStore %16 %14
285 %19 = OpAccessChain %15 %11 %17
286 OpStore %19 %18
287 %23 = OpAccessChain %15 %11 %13
288 %24 = OpLoad %6 %23
289 %25 = OpAccessChain %15 %11 %17
290 %26 = OpLoad %6 %25
291 %27 = OpCompositeConstruct %20 %24 %26
292 OpStore %22 %27
293 %28 = OpAccessChain %15 %11 %13
294 %29 = OpLoad %6 %28
295 %30 = OpAccessChain %15 %11 %17
296 %31 = OpLoad %6 %30
297 %33 = OpFOrdGreaterThan %32 %29 %31
298 %202 = OpCompositeConstruct %47 %33 %50 %50
299 OpSelectionMerge %35 None
300 OpBranchConditional %33 %34 %35
301 %34 = OpLabel
302 %43 = OpAccessChain %42 %39 %17
303 OpStore %43 %41
304 %45 = OpLoad %20 %22
305 %200 = OpCompositeConstruct %37 %41 %45 %27
306 %46 = OpAccessChain %42 %39 %44
307 OpStore %46 %45
308 OpBranch %35
309 %35 = OpLabel
310 %52 = OpAccessChain %51 %49 %13
311 OpStore %52 %50
312 %53 = OpAccessChain %51 %49 %13
313 %54 = OpLoad %32 %53
314 %55 = OpAccessChain %51 %49 %17
315 OpStore %55 %54
316 %64 = OpAccessChain %63 %60 %13 %13
317 %203 = OpCompositeConstruct %58 %69 %100
318 OpStore %64 %62
319 %71 = OpAccessChain %70 %60 %17
320 %201 = OpCompositeConstruct %9 %24 %40
321 OpStore %71 %69
322 OpReturn
323 OpFunctionEnd
324 )";
325
326 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
327 }
328
TEST(TransformationCompositeConstructTest,ConstructMatrices)329 TEST(TransformationCompositeConstructTest, ConstructMatrices) {
330 std::string shader = R"(
331 OpCapability Shader
332 %1 = OpExtInstImport "GLSL.std.450"
333 OpMemoryModel Logical GLSL450
334 OpEntryPoint Fragment %4 "main"
335 OpExecutionMode %4 OriginUpperLeft
336 OpSource ESSL 310
337 OpName %4 "main"
338 OpName %9 "v1"
339 OpName %12 "v2"
340 OpName %14 "v3"
341 OpName %19 "v4"
342 OpName %26 "v5"
343 OpName %29 "v6"
344 OpName %34 "m34"
345 OpName %37 "m43"
346 OpName %43 "vecs"
347 %2 = OpTypeVoid
348 %3 = OpTypeFunction %2
349 %6 = OpTypeFloat 32
350 %7 = OpTypeVector %6 3
351 %8 = OpTypePointer Function %7
352 %10 = OpConstant %6 1
353 %11 = OpConstantComposite %7 %10 %10 %10
354 %17 = OpTypeVector %6 4
355 %18 = OpTypePointer Function %17
356 %21 = OpConstant %6 2
357 %32 = OpTypeMatrix %17 3
358 %33 = OpTypePointer Private %32
359 %34 = OpVariable %33 Private
360 %35 = OpTypeMatrix %7 4
361 %36 = OpTypePointer Private %35
362 %37 = OpVariable %36 Private
363 %38 = OpTypeVector %6 2
364 %39 = OpTypeInt 32 0
365 %40 = OpConstant %39 3
366 %41 = OpTypeArray %38 %40
367 %42 = OpTypePointer Private %41
368 %43 = OpVariable %42 Private
369 %100 = OpUndef %7
370 %101 = OpUndef %17
371 %4 = OpFunction %2 None %3
372 %5 = OpLabel
373 %9 = OpVariable %8 Function
374 %12 = OpVariable %8 Function
375 %14 = OpVariable %8 Function
376 %19 = OpVariable %18 Function
377 %26 = OpVariable %18 Function
378 %29 = OpVariable %18 Function
379 OpStore %9 %11
380 %13 = OpLoad %7 %9
381 OpStore %12 %13
382 %15 = OpLoad %7 %12
383 %16 = OpVectorShuffle %7 %15 %15 2 1 0
384 OpStore %14 %16
385 %20 = OpLoad %7 %14
386 %22 = OpCompositeExtract %6 %20 0
387 %23 = OpCompositeExtract %6 %20 1
388 %24 = OpCompositeExtract %6 %20 2
389 %25 = OpCompositeConstruct %17 %22 %23 %24 %21
390 OpStore %19 %25
391 %27 = OpLoad %17 %19
392 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
393 OpStore %26 %28
394 %30 = OpLoad %7 %9
395 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
396 OpStore %29 %31
397 OpReturn
398 OpFunctionEnd
399 )";
400
401 const auto env = SPV_ENV_UNIVERSAL_1_3;
402 const auto consumer = nullptr;
403 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
404 spvtools::ValidatorOptions validator_options;
405 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
406 kConsoleMessageConsumer));
407 TransformationContext transformation_context(
408 MakeUnique<FactManager>(context.get()), validator_options);
409 // make a mat3x4
410 TransformationCompositeConstruct make_mat34(
411 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
412 // Bad: %35 is mat4x3, not mat3x4.
413 TransformationCompositeConstruct make_mat34_bad(
414 35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
415 ASSERT_TRUE(make_mat34.IsApplicable(context.get(), transformation_context));
416 ASSERT_FALSE(
417 make_mat34_bad.IsApplicable(context.get(), transformation_context));
418 ApplyAndCheckFreshIds(make_mat34, context.get(), &transformation_context);
419 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
420 kConsoleMessageConsumer));
421 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
422 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
423 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
424 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
425 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
426 MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2})));
427
428 // make a mat4x3
429 TransformationCompositeConstruct make_mat43(
430 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
431 // Bad: %25 does not match the matrix's column type.
432 TransformationCompositeConstruct make_mat43_bad(
433 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
434 ASSERT_TRUE(make_mat43.IsApplicable(context.get(), transformation_context));
435 ASSERT_FALSE(
436 make_mat43_bad.IsApplicable(context.get(), transformation_context));
437 ApplyAndCheckFreshIds(make_mat43, context.get(), &transformation_context);
438 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
439 kConsoleMessageConsumer));
440 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
441 MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0})));
442 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
443 MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1})));
444 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
445 MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2})));
446 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
447 MakeDataDescriptor(100, {}), MakeDataDescriptor(201, {3})));
448
449 std::string after_transformation = R"(
450 OpCapability Shader
451 %1 = OpExtInstImport "GLSL.std.450"
452 OpMemoryModel Logical GLSL450
453 OpEntryPoint Fragment %4 "main"
454 OpExecutionMode %4 OriginUpperLeft
455 OpSource ESSL 310
456 OpName %4 "main"
457 OpName %9 "v1"
458 OpName %12 "v2"
459 OpName %14 "v3"
460 OpName %19 "v4"
461 OpName %26 "v5"
462 OpName %29 "v6"
463 OpName %34 "m34"
464 OpName %37 "m43"
465 OpName %43 "vecs"
466 %2 = OpTypeVoid
467 %3 = OpTypeFunction %2
468 %6 = OpTypeFloat 32
469 %7 = OpTypeVector %6 3
470 %8 = OpTypePointer Function %7
471 %10 = OpConstant %6 1
472 %11 = OpConstantComposite %7 %10 %10 %10
473 %17 = OpTypeVector %6 4
474 %18 = OpTypePointer Function %17
475 %21 = OpConstant %6 2
476 %32 = OpTypeMatrix %17 3
477 %33 = OpTypePointer Private %32
478 %34 = OpVariable %33 Private
479 %35 = OpTypeMatrix %7 4
480 %36 = OpTypePointer Private %35
481 %37 = OpVariable %36 Private
482 %38 = OpTypeVector %6 2
483 %39 = OpTypeInt 32 0
484 %40 = OpConstant %39 3
485 %41 = OpTypeArray %38 %40
486 %42 = OpTypePointer Private %41
487 %43 = OpVariable %42 Private
488 %100 = OpUndef %7
489 %101 = OpUndef %17
490 %4 = OpFunction %2 None %3
491 %5 = OpLabel
492 %9 = OpVariable %8 Function
493 %12 = OpVariable %8 Function
494 %14 = OpVariable %8 Function
495 %19 = OpVariable %18 Function
496 %26 = OpVariable %18 Function
497 %29 = OpVariable %18 Function
498 OpStore %9 %11
499 %13 = OpLoad %7 %9
500 OpStore %12 %13
501 %15 = OpLoad %7 %12
502 %16 = OpVectorShuffle %7 %15 %15 2 1 0
503 OpStore %14 %16
504 %20 = OpLoad %7 %14
505 %22 = OpCompositeExtract %6 %20 0
506 %23 = OpCompositeExtract %6 %20 1
507 %24 = OpCompositeExtract %6 %20 2
508 %25 = OpCompositeConstruct %17 %22 %23 %24 %21
509 OpStore %19 %25
510 %27 = OpLoad %17 %19
511 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
512 OpStore %26 %28
513 %30 = OpLoad %7 %9
514 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
515 %201 = OpCompositeConstruct %35 %11 %13 %16 %100
516 OpStore %29 %31
517 %200 = OpCompositeConstruct %32 %25 %28 %31
518 OpReturn
519 OpFunctionEnd
520 )";
521
522 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
523 }
524
TEST(TransformationCompositeConstructTest,ConstructStructs)525 TEST(TransformationCompositeConstructTest, ConstructStructs) {
526 std::string shader = R"(
527 OpCapability Shader
528 %1 = OpExtInstImport "GLSL.std.450"
529 OpMemoryModel Logical GLSL450
530 OpEntryPoint Fragment %4 "main"
531 OpExecutionMode %4 OriginUpperLeft
532 OpSource ESSL 310
533 OpName %4 "main"
534 OpName %9 "Inner"
535 OpMemberName %9 0 "a"
536 OpMemberName %9 1 "b"
537 OpName %11 "i1"
538 OpName %22 "i2"
539 OpName %33 "Outer"
540 OpMemberName %33 0 "c"
541 OpMemberName %33 1 "d"
542 OpMemberName %33 2 "e"
543 OpName %35 "o"
544 %2 = OpTypeVoid
545 %3 = OpTypeFunction %2
546 %6 = OpTypeFloat 32
547 %7 = OpTypeVector %6 2
548 %8 = OpTypeInt 32 1
549 %9 = OpTypeStruct %7 %8
550 %10 = OpTypePointer Function %9
551 %12 = OpConstant %8 0
552 %13 = OpConstant %6 2
553 %14 = OpTypeInt 32 0
554 %15 = OpConstant %14 0
555 %16 = OpTypePointer Function %6
556 %18 = OpConstant %8 1
557 %19 = OpConstant %8 3
558 %20 = OpTypePointer Function %8
559 %23 = OpTypePointer Function %7
560 %31 = OpConstant %14 2
561 %32 = OpTypeArray %9 %31
562 %33 = OpTypeStruct %32 %9 %6
563 %34 = OpTypePointer Function %33
564 %36 = OpConstant %6 1
565 %37 = OpConstantComposite %7 %36 %13
566 %38 = OpConstant %8 2
567 %39 = OpConstantComposite %9 %37 %38
568 %40 = OpConstant %6 3
569 %41 = OpConstant %6 4
570 %42 = OpConstantComposite %7 %40 %41
571 %56 = OpConstant %6 5
572 %100 = OpUndef %9
573 %4 = OpFunction %2 None %3
574 %5 = OpLabel
575 %11 = OpVariable %10 Function
576 %22 = OpVariable %10 Function
577 %35 = OpVariable %34 Function
578 %17 = OpAccessChain %16 %11 %12 %15
579 OpStore %17 %13
580 %21 = OpAccessChain %20 %11 %18
581 OpStore %21 %19
582 %24 = OpAccessChain %23 %11 %12
583 %25 = OpLoad %7 %24
584 %26 = OpAccessChain %23 %22 %12
585 OpStore %26 %25
586 %27 = OpAccessChain %20 %11 %18
587 %28 = OpLoad %8 %27
588 %29 = OpIAdd %8 %28 %18
589 %30 = OpAccessChain %20 %22 %18
590 OpStore %30 %29
591 %43 = OpAccessChain %20 %11 %18
592 %44 = OpLoad %8 %43
593 %45 = OpCompositeConstruct %9 %42 %44
594 %46 = OpCompositeConstruct %32 %39 %45
595 %47 = OpLoad %9 %22
596 %48 = OpCompositeConstruct %33 %46 %47 %40
597 OpStore %35 %48
598 %49 = OpLoad %9 %11
599 %50 = OpAccessChain %10 %35 %12 %12
600 OpStore %50 %49
601 %51 = OpLoad %9 %22
602 %52 = OpAccessChain %10 %35 %12 %18
603 OpStore %52 %51
604 %53 = OpAccessChain %10 %35 %12 %12
605 %54 = OpLoad %9 %53
606 %55 = OpAccessChain %10 %35 %18
607 OpStore %55 %54
608 %57 = OpAccessChain %16 %35 %38
609 OpStore %57 %56
610 OpReturn
611 OpFunctionEnd
612 )";
613
614 const auto env = SPV_ENV_UNIVERSAL_1_3;
615 const auto consumer = nullptr;
616 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
617 spvtools::ValidatorOptions validator_options;
618 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
619 kConsoleMessageConsumer));
620 TransformationContext transformation_context(
621 MakeUnique<FactManager>(context.get()), validator_options);
622 // make an Inner
623 TransformationCompositeConstruct make_inner(
624 9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
625 // Bad: Too few fields to make the struct.
626 TransformationCompositeConstruct make_inner_bad(
627 9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
628 ASSERT_TRUE(make_inner.IsApplicable(context.get(), transformation_context));
629 ASSERT_FALSE(
630 make_inner_bad.IsApplicable(context.get(), transformation_context));
631 ApplyAndCheckFreshIds(make_inner, context.get(), &transformation_context);
632 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
633 kConsoleMessageConsumer));
634 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
635 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
636 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
637 MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1})));
638
639 // make an Outer
640 TransformationCompositeConstruct make_outer(
641 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0),
642 201);
643 // Bad: %200 is not available at the desired program point.
644 TransformationCompositeConstruct make_outer_bad(
645 33, {46, 200, 56},
646 MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201);
647 ASSERT_TRUE(make_outer.IsApplicable(context.get(), transformation_context));
648 ASSERT_FALSE(
649 make_outer_bad.IsApplicable(context.get(), transformation_context));
650 ApplyAndCheckFreshIds(make_outer, context.get(), &transformation_context);
651 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
652 kConsoleMessageConsumer));
653 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
654 MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0})));
655 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
656 MakeDataDescriptor(200, {}), MakeDataDescriptor(201, {1})));
657 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
658 MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2})));
659
660 std::string after_transformation = R"(
661 OpCapability Shader
662 %1 = OpExtInstImport "GLSL.std.450"
663 OpMemoryModel Logical GLSL450
664 OpEntryPoint Fragment %4 "main"
665 OpExecutionMode %4 OriginUpperLeft
666 OpSource ESSL 310
667 OpName %4 "main"
668 OpName %9 "Inner"
669 OpMemberName %9 0 "a"
670 OpMemberName %9 1 "b"
671 OpName %11 "i1"
672 OpName %22 "i2"
673 OpName %33 "Outer"
674 OpMemberName %33 0 "c"
675 OpMemberName %33 1 "d"
676 OpMemberName %33 2 "e"
677 OpName %35 "o"
678 %2 = OpTypeVoid
679 %3 = OpTypeFunction %2
680 %6 = OpTypeFloat 32
681 %7 = OpTypeVector %6 2
682 %8 = OpTypeInt 32 1
683 %9 = OpTypeStruct %7 %8
684 %10 = OpTypePointer Function %9
685 %12 = OpConstant %8 0
686 %13 = OpConstant %6 2
687 %14 = OpTypeInt 32 0
688 %15 = OpConstant %14 0
689 %16 = OpTypePointer Function %6
690 %18 = OpConstant %8 1
691 %19 = OpConstant %8 3
692 %20 = OpTypePointer Function %8
693 %23 = OpTypePointer Function %7
694 %31 = OpConstant %14 2
695 %32 = OpTypeArray %9 %31
696 %33 = OpTypeStruct %32 %9 %6
697 %34 = OpTypePointer Function %33
698 %36 = OpConstant %6 1
699 %37 = OpConstantComposite %7 %36 %13
700 %38 = OpConstant %8 2
701 %39 = OpConstantComposite %9 %37 %38
702 %40 = OpConstant %6 3
703 %41 = OpConstant %6 4
704 %42 = OpConstantComposite %7 %40 %41
705 %56 = OpConstant %6 5
706 %100 = OpUndef %9
707 %4 = OpFunction %2 None %3
708 %5 = OpLabel
709 %11 = OpVariable %10 Function
710 %22 = OpVariable %10 Function
711 %35 = OpVariable %34 Function
712 %17 = OpAccessChain %16 %11 %12 %15
713 OpStore %17 %13
714 %21 = OpAccessChain %20 %11 %18
715 OpStore %21 %19
716 %24 = OpAccessChain %23 %11 %12
717 %25 = OpLoad %7 %24
718 %26 = OpAccessChain %23 %22 %12
719 OpStore %26 %25
720 %27 = OpAccessChain %20 %11 %18
721 %28 = OpLoad %8 %27
722 %29 = OpIAdd %8 %28 %18
723 %30 = OpAccessChain %20 %22 %18
724 OpStore %30 %29
725 %43 = OpAccessChain %20 %11 %18
726 %44 = OpLoad %8 %43
727 %45 = OpCompositeConstruct %9 %42 %44
728 %46 = OpCompositeConstruct %32 %39 %45
729 %47 = OpLoad %9 %22
730 %48 = OpCompositeConstruct %33 %46 %47 %40
731 OpStore %35 %48
732 %49 = OpLoad %9 %11
733 %50 = OpAccessChain %10 %35 %12 %12
734 OpStore %50 %49
735 %51 = OpLoad %9 %22
736 %52 = OpAccessChain %10 %35 %12 %18
737 OpStore %52 %51
738 %53 = OpAccessChain %10 %35 %12 %12
739 %54 = OpLoad %9 %53
740 %55 = OpAccessChain %10 %35 %18
741 OpStore %55 %54
742 %200 = OpCompositeConstruct %9 %25 %19
743 %201 = OpCompositeConstruct %33 %46 %200 %56
744 %57 = OpAccessChain %16 %35 %38
745 OpStore %57 %56
746 OpReturn
747 OpFunctionEnd
748 )";
749
750 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
751 }
752
TEST(TransformationCompositeConstructTest,ConstructVectors)753 TEST(TransformationCompositeConstructTest, ConstructVectors) {
754 std::string shader = R"(
755 OpCapability Shader
756 %1 = OpExtInstImport "GLSL.std.450"
757 OpMemoryModel Logical GLSL450
758 OpEntryPoint Fragment %4 "main"
759 OpExecutionMode %4 OriginUpperLeft
760 OpSource ESSL 310
761 OpName %4 "main"
762 OpName %9 "v2"
763 OpName %27 "v3"
764 OpName %46 "v4"
765 OpName %53 "iv2"
766 OpName %61 "uv3"
767 OpName %72 "bv4"
768 OpName %88 "uv2"
769 OpName %95 "bv3"
770 OpName %104 "bv2"
771 OpName %116 "iv3"
772 OpName %124 "iv4"
773 OpName %133 "uv4"
774 %2 = OpTypeVoid
775 %3 = OpTypeFunction %2
776 %6 = OpTypeFloat 32
777 %7 = OpTypeVector %6 2
778 %8 = OpTypePointer Function %7
779 %10 = OpConstant %6 1
780 %11 = OpConstant %6 2
781 %12 = OpConstantComposite %7 %10 %11
782 %13 = OpTypeInt 32 0
783 %14 = OpConstant %13 0
784 %15 = OpTypePointer Function %6
785 %18 = OpConstant %13 1
786 %21 = OpTypeBool
787 %25 = OpTypeVector %6 3
788 %26 = OpTypePointer Function %25
789 %33 = OpConstant %6 3
790 %34 = OpConstant %6 -0.756802499
791 %38 = OpConstant %13 2
792 %44 = OpTypeVector %6 4
793 %45 = OpTypePointer Function %44
794 %50 = OpTypeInt 32 1
795 %51 = OpTypeVector %50 2
796 %52 = OpTypePointer Function %51
797 %57 = OpTypePointer Function %50
798 %59 = OpTypeVector %13 3
799 %60 = OpTypePointer Function %59
800 %65 = OpConstant %13 3
801 %67 = OpTypePointer Function %13
802 %70 = OpTypeVector %21 4
803 %71 = OpTypePointer Function %70
804 %73 = OpConstantTrue %21
805 %74 = OpTypePointer Function %21
806 %86 = OpTypeVector %13 2
807 %87 = OpTypePointer Function %86
808 %93 = OpTypeVector %21 3
809 %94 = OpTypePointer Function %93
810 %102 = OpTypeVector %21 2
811 %103 = OpTypePointer Function %102
812 %111 = OpConstantFalse %21
813 %114 = OpTypeVector %50 3
814 %115 = OpTypePointer Function %114
815 %117 = OpConstant %50 3
816 %122 = OpTypeVector %50 4
817 %123 = OpTypePointer Function %122
818 %131 = OpTypeVector %13 4
819 %132 = OpTypePointer Function %131
820 %4 = OpFunction %2 None %3
821 %5 = OpLabel
822 %9 = OpVariable %8 Function
823 %27 = OpVariable %26 Function
824 %46 = OpVariable %45 Function
825 %53 = OpVariable %52 Function
826 %61 = OpVariable %60 Function
827 %72 = OpVariable %71 Function
828 %88 = OpVariable %87 Function
829 %95 = OpVariable %94 Function
830 %104 = OpVariable %103 Function
831 %116 = OpVariable %115 Function
832 %124 = OpVariable %123 Function
833 %133 = OpVariable %132 Function
834 OpStore %9 %12
835 %16 = OpAccessChain %15 %9 %14
836 %17 = OpLoad %6 %16
837 %19 = OpAccessChain %15 %9 %18
838 %20 = OpLoad %6 %19
839 %22 = OpFOrdGreaterThan %21 %17 %20
840 OpSelectionMerge %24 None
841 OpBranchConditional %22 %23 %101
842 %23 = OpLabel
843 %28 = OpAccessChain %15 %9 %14
844 %29 = OpLoad %6 %28
845 %30 = OpAccessChain %15 %9 %18
846 %31 = OpLoad %6 %30
847 %32 = OpFAdd %6 %29 %31
848 %35 = OpCompositeConstruct %25 %32 %33 %34
849 OpStore %27 %35
850 %36 = OpAccessChain %15 %27 %14
851 %37 = OpLoad %6 %36
852 %39 = OpAccessChain %15 %27 %38
853 %40 = OpLoad %6 %39
854 %41 = OpFOrdLessThan %21 %37 %40
855 OpSelectionMerge %43 None
856 OpBranchConditional %41 %42 %69
857 %42 = OpLabel
858 %47 = OpAccessChain %15 %9 %18
859 %48 = OpLoad %6 %47
860 %49 = OpAccessChain %15 %46 %14
861 OpStore %49 %48
862 %54 = OpAccessChain %15 %27 %38
863 %55 = OpLoad %6 %54
864 %56 = OpConvertFToS %50 %55
865 %58 = OpAccessChain %57 %53 %14
866 OpStore %58 %56
867 %62 = OpAccessChain %15 %46 %14
868 %63 = OpLoad %6 %62
869 %64 = OpConvertFToU %13 %63
870 %66 = OpIAdd %13 %64 %65
871 %68 = OpAccessChain %67 %61 %14
872 OpStore %68 %66
873 OpBranch %43
874 %69 = OpLabel
875 %75 = OpAccessChain %74 %72 %14
876 OpStore %75 %73
877 %76 = OpAccessChain %74 %72 %14
878 %77 = OpLoad %21 %76
879 %78 = OpLogicalNot %21 %77
880 %79 = OpAccessChain %74 %72 %18
881 OpStore %79 %78
882 %80 = OpAccessChain %74 %72 %14
883 %81 = OpLoad %21 %80
884 %82 = OpAccessChain %74 %72 %18
885 %83 = OpLoad %21 %82
886 %84 = OpLogicalAnd %21 %81 %83
887 %85 = OpAccessChain %74 %72 %38
888 OpStore %85 %84
889 %89 = OpAccessChain %67 %88 %14
890 %90 = OpLoad %13 %89
891 %91 = OpINotEqual %21 %90 %14
892 %92 = OpAccessChain %74 %72 %65
893 OpStore %92 %91
894 OpBranch %43
895 %43 = OpLabel
896 %96 = OpLoad %70 %72
897 %97 = OpCompositeExtract %21 %96 0
898 %98 = OpCompositeExtract %21 %96 1
899 %99 = OpCompositeExtract %21 %96 2
900 %100 = OpCompositeConstruct %93 %97 %98 %99
901 OpStore %95 %100
902 OpBranch %24
903 %101 = OpLabel
904 %105 = OpAccessChain %67 %88 %14
905 %106 = OpLoad %13 %105
906 %107 = OpINotEqual %21 %106 %14
907 %108 = OpCompositeConstruct %102 %107 %107
908 OpStore %104 %108
909 OpBranch %24
910 %24 = OpLabel
911 %109 = OpAccessChain %74 %104 %18
912 %110 = OpLoad %21 %109
913 %112 = OpLogicalOr %21 %110 %111
914 %113 = OpAccessChain %74 %104 %14
915 OpStore %113 %112
916 %118 = OpAccessChain %57 %116 %14
917 OpStore %118 %117
918 %119 = OpAccessChain %57 %116 %14
919 %120 = OpLoad %50 %119
920 %121 = OpAccessChain %57 %53 %18
921 OpStore %121 %120
922 %125 = OpAccessChain %57 %116 %14
923 %126 = OpLoad %50 %125
924 %127 = OpAccessChain %57 %53 %18
925 %128 = OpLoad %50 %127
926 %129 = OpIAdd %50 %126 %128
927 %130 = OpAccessChain %57 %124 %65
928 OpStore %130 %129
929 %134 = OpAccessChain %57 %116 %14
930 %135 = OpLoad %50 %134
931 %136 = OpBitcast %13 %135
932 %137 = OpAccessChain %67 %133 %14
933 OpStore %137 %136
934 OpReturn
935 OpFunctionEnd
936 )";
937
938 const auto env = SPV_ENV_UNIVERSAL_1_3;
939 const auto consumer = nullptr;
940 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
941 spvtools::ValidatorOptions validator_options;
942 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
943 kConsoleMessageConsumer));
944 TransformationContext transformation_context(
945 MakeUnique<FactManager>(context.get()), validator_options);
946 TransformationCompositeConstruct make_vec2(
947 7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
948 // Bad: not enough data for a vec2
949 TransformationCompositeConstruct make_vec2_bad(
950 7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
951 ASSERT_TRUE(make_vec2.IsApplicable(context.get(), transformation_context));
952 ASSERT_FALSE(
953 make_vec2_bad.IsApplicable(context.get(), transformation_context));
954 ApplyAndCheckFreshIds(make_vec2, context.get(), &transformation_context);
955 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
956 kConsoleMessageConsumer));
957 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
958 MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0})));
959 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
960 MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1})));
961
962 TransformationCompositeConstruct make_vec3(
963 25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
964 201);
965 // Bad: too much data for a vec3
966 TransformationCompositeConstruct make_vec3_bad(
967 25, {12, 32, 32},
968 MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201);
969 ASSERT_TRUE(make_vec3.IsApplicable(context.get(), transformation_context));
970 ASSERT_FALSE(
971 make_vec3_bad.IsApplicable(context.get(), transformation_context));
972 ApplyAndCheckFreshIds(make_vec3, context.get(), &transformation_context);
973 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
974 kConsoleMessageConsumer));
975 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
976 MakeDataDescriptor(12, {0}), MakeDataDescriptor(201, {0})));
977 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
978 MakeDataDescriptor(12, {1}), MakeDataDescriptor(201, {1})));
979 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
980 MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2})));
981
982 TransformationCompositeConstruct make_vec4(
983 44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
984 202);
985 // Bad: id 48 is not available at the insertion points
986 TransformationCompositeConstruct make_vec4_bad(
987 44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
988 202);
989 ASSERT_TRUE(make_vec4.IsApplicable(context.get(), transformation_context));
990 ASSERT_FALSE(
991 make_vec4_bad.IsApplicable(context.get(), transformation_context));
992 ApplyAndCheckFreshIds(make_vec4, context.get(), &transformation_context);
993 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
994 kConsoleMessageConsumer));
995 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
996 MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0})));
997 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
998 MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1})));
999 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1000 MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2})));
1001 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1002 MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3})));
1003
1004 TransformationCompositeConstruct make_ivec2(
1005 51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
1006 // Bad: if 128 is not available at the instruction that defines 128
1007 TransformationCompositeConstruct make_ivec2_bad(
1008 51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
1009 ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), transformation_context));
1010 ASSERT_FALSE(
1011 make_ivec2_bad.IsApplicable(context.get(), transformation_context));
1012 ApplyAndCheckFreshIds(make_ivec2, context.get(), &transformation_context);
1013 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1014 kConsoleMessageConsumer));
1015 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1016 MakeDataDescriptor(126, {}), MakeDataDescriptor(203, {0})));
1017 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1018 MakeDataDescriptor(120, {}), MakeDataDescriptor(203, {1})));
1019
1020 TransformationCompositeConstruct make_ivec3(
1021 114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
1022 204);
1023 // Bad because 1300 is not an id
1024 TransformationCompositeConstruct make_ivec3_bad(
1025 114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
1026 204);
1027 ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), transformation_context));
1028 ASSERT_FALSE(
1029 make_ivec3_bad.IsApplicable(context.get(), transformation_context));
1030 ApplyAndCheckFreshIds(make_ivec3, context.get(), &transformation_context);
1031 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1032 kConsoleMessageConsumer));
1033 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1034 MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0})));
1035 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1036 MakeDataDescriptor(117, {}), MakeDataDescriptor(204, {1})));
1037 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1038 MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2})));
1039
1040 TransformationCompositeConstruct make_ivec4(
1041 122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
1042 205);
1043 // Bad because 86 is the wrong type.
1044 TransformationCompositeConstruct make_ivec4_bad(
1045 86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
1046 205);
1047 ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), transformation_context));
1048 ASSERT_FALSE(
1049 make_ivec4_bad.IsApplicable(context.get(), transformation_context));
1050 ApplyAndCheckFreshIds(make_ivec4, context.get(), &transformation_context);
1051 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1052 kConsoleMessageConsumer));
1053 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1054 MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0})));
1055 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1056 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {1})));
1057 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1058 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {2})));
1059 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1060 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {3})));
1061
1062 TransformationCompositeConstruct make_uvec2(
1063 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
1064 TransformationCompositeConstruct make_uvec2_bad(
1065 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206);
1066 ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), transformation_context));
1067 ASSERT_FALSE(
1068 make_uvec2_bad.IsApplicable(context.get(), transformation_context));
1069 ApplyAndCheckFreshIds(make_uvec2, context.get(), &transformation_context);
1070 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1071 kConsoleMessageConsumer));
1072 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1073 MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0})));
1074 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1075 MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1})));
1076
1077 TransformationCompositeConstruct make_uvec3(
1078 59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
1079 // Bad because 1300 is not an id
1080 TransformationCompositeConstruct make_uvec3_bad(
1081 59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
1082 ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), transformation_context));
1083 ASSERT_FALSE(
1084 make_uvec3_bad.IsApplicable(context.get(), transformation_context));
1085 ApplyAndCheckFreshIds(make_uvec3, context.get(), &transformation_context);
1086 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1087 kConsoleMessageConsumer));
1088 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1089 MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0})));
1090 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1091 MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1})));
1092 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1093 MakeDataDescriptor(136, {}), MakeDataDescriptor(207, {2})));
1094
1095 TransformationCompositeConstruct make_uvec4(
1096 131, {14, 18, 136, 136},
1097 MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
1098 // Bad because 86 is the wrong type.
1099 TransformationCompositeConstruct make_uvec4_bad(
1100 86, {14, 18, 136, 136},
1101 MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
1102 ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), transformation_context));
1103 ASSERT_FALSE(
1104 make_uvec4_bad.IsApplicable(context.get(), transformation_context));
1105 ApplyAndCheckFreshIds(make_uvec4, context.get(), &transformation_context);
1106 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1107 kConsoleMessageConsumer));
1108 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1109 MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0})));
1110 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1111 MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1})));
1112 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1113 MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {2})));
1114 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1115 MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {3})));
1116
1117 TransformationCompositeConstruct make_bvec2(
1118 102,
1119 {
1120 111,
1121 41,
1122 },
1123 MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209);
1124 // Bad because 0 is not a valid base instruction id
1125 TransformationCompositeConstruct make_bvec2_bad(
1126 102,
1127 {
1128 111,
1129 41,
1130 },
1131 MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209);
1132 ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), transformation_context));
1133 ASSERT_FALSE(
1134 make_bvec2_bad.IsApplicable(context.get(), transformation_context));
1135 ApplyAndCheckFreshIds(make_bvec2, context.get(), &transformation_context);
1136 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1137 kConsoleMessageConsumer));
1138 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1139 MakeDataDescriptor(111, {}), MakeDataDescriptor(209, {0})));
1140 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1141 MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1})));
1142
1143 TransformationCompositeConstruct make_bvec3(
1144 93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
1145 // Bad because there are too many components for a bvec3
1146 TransformationCompositeConstruct make_bvec3_bad(
1147 93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
1148 ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), transformation_context));
1149 ASSERT_FALSE(
1150 make_bvec3_bad.IsApplicable(context.get(), transformation_context));
1151 ApplyAndCheckFreshIds(make_bvec3, context.get(), &transformation_context);
1152 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1153 kConsoleMessageConsumer));
1154 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1155 MakeDataDescriptor(108, {0}), MakeDataDescriptor(210, {0})));
1156 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1157 MakeDataDescriptor(108, {1}), MakeDataDescriptor(210, {1})));
1158 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1159 MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2})));
1160
1161 TransformationCompositeConstruct make_bvec4(
1162 70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
1163 // Bad because 21 is a type, not a result id
1164 TransformationCompositeConstruct make_bvec4_bad(
1165 70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
1166 ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), transformation_context));
1167 ASSERT_FALSE(
1168 make_bvec4_bad.IsApplicable(context.get(), transformation_context));
1169 ApplyAndCheckFreshIds(make_bvec4, context.get(), &transformation_context);
1170 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1171 kConsoleMessageConsumer));
1172 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1173 MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {0})));
1174 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1175 MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {1})));
1176 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1177 MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {2})));
1178 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1179 MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {3})));
1180
1181 std::string after_transformation = R"(
1182 OpCapability Shader
1183 %1 = OpExtInstImport "GLSL.std.450"
1184 OpMemoryModel Logical GLSL450
1185 OpEntryPoint Fragment %4 "main"
1186 OpExecutionMode %4 OriginUpperLeft
1187 OpSource ESSL 310
1188 OpName %4 "main"
1189 OpName %9 "v2"
1190 OpName %27 "v3"
1191 OpName %46 "v4"
1192 OpName %53 "iv2"
1193 OpName %61 "uv3"
1194 OpName %72 "bv4"
1195 OpName %88 "uv2"
1196 OpName %95 "bv3"
1197 OpName %104 "bv2"
1198 OpName %116 "iv3"
1199 OpName %124 "iv4"
1200 OpName %133 "uv4"
1201 %2 = OpTypeVoid
1202 %3 = OpTypeFunction %2
1203 %6 = OpTypeFloat 32
1204 %7 = OpTypeVector %6 2
1205 %8 = OpTypePointer Function %7
1206 %10 = OpConstant %6 1
1207 %11 = OpConstant %6 2
1208 %12 = OpConstantComposite %7 %10 %11
1209 %13 = OpTypeInt 32 0
1210 %14 = OpConstant %13 0
1211 %15 = OpTypePointer Function %6
1212 %18 = OpConstant %13 1
1213 %21 = OpTypeBool
1214 %25 = OpTypeVector %6 3
1215 %26 = OpTypePointer Function %25
1216 %33 = OpConstant %6 3
1217 %34 = OpConstant %6 -0.756802499
1218 %38 = OpConstant %13 2
1219 %44 = OpTypeVector %6 4
1220 %45 = OpTypePointer Function %44
1221 %50 = OpTypeInt 32 1
1222 %51 = OpTypeVector %50 2
1223 %52 = OpTypePointer Function %51
1224 %57 = OpTypePointer Function %50
1225 %59 = OpTypeVector %13 3
1226 %60 = OpTypePointer Function %59
1227 %65 = OpConstant %13 3
1228 %67 = OpTypePointer Function %13
1229 %70 = OpTypeVector %21 4
1230 %71 = OpTypePointer Function %70
1231 %73 = OpConstantTrue %21
1232 %74 = OpTypePointer Function %21
1233 %86 = OpTypeVector %13 2
1234 %87 = OpTypePointer Function %86
1235 %93 = OpTypeVector %21 3
1236 %94 = OpTypePointer Function %93
1237 %102 = OpTypeVector %21 2
1238 %103 = OpTypePointer Function %102
1239 %111 = OpConstantFalse %21
1240 %114 = OpTypeVector %50 3
1241 %115 = OpTypePointer Function %114
1242 %117 = OpConstant %50 3
1243 %122 = OpTypeVector %50 4
1244 %123 = OpTypePointer Function %122
1245 %131 = OpTypeVector %13 4
1246 %132 = OpTypePointer Function %131
1247 %4 = OpFunction %2 None %3
1248 %5 = OpLabel
1249 %9 = OpVariable %8 Function
1250 %27 = OpVariable %26 Function
1251 %46 = OpVariable %45 Function
1252 %53 = OpVariable %52 Function
1253 %61 = OpVariable %60 Function
1254 %72 = OpVariable %71 Function
1255 %88 = OpVariable %87 Function
1256 %95 = OpVariable %94 Function
1257 %104 = OpVariable %103 Function
1258 %116 = OpVariable %115 Function
1259 %124 = OpVariable %123 Function
1260 %133 = OpVariable %132 Function
1261 OpStore %9 %12
1262 %206 = OpCompositeConstruct %86 %18 %38
1263 %16 = OpAccessChain %15 %9 %14
1264 %17 = OpLoad %6 %16
1265 %19 = OpAccessChain %15 %9 %18
1266 %20 = OpLoad %6 %19
1267 %22 = OpFOrdGreaterThan %21 %17 %20
1268 OpSelectionMerge %24 None
1269 OpBranchConditional %22 %23 %101
1270 %23 = OpLabel
1271 %28 = OpAccessChain %15 %9 %14
1272 %29 = OpLoad %6 %28
1273 %30 = OpAccessChain %15 %9 %18
1274 %31 = OpLoad %6 %30
1275 %32 = OpFAdd %6 %29 %31
1276 %201 = OpCompositeConstruct %25 %12 %32
1277 %35 = OpCompositeConstruct %25 %32 %33 %34
1278 OpStore %27 %35
1279 %36 = OpAccessChain %15 %27 %14
1280 %37 = OpLoad %6 %36
1281 %39 = OpAccessChain %15 %27 %38
1282 %40 = OpLoad %6 %39
1283 %41 = OpFOrdLessThan %21 %37 %40
1284 OpSelectionMerge %43 None
1285 OpBranchConditional %41 %42 %69
1286 %42 = OpLabel
1287 %47 = OpAccessChain %15 %9 %18
1288 %48 = OpLoad %6 %47
1289 %49 = OpAccessChain %15 %46 %14
1290 OpStore %49 %48
1291 %54 = OpAccessChain %15 %27 %38
1292 %55 = OpLoad %6 %54
1293 %56 = OpConvertFToS %50 %55
1294 %58 = OpAccessChain %57 %53 %14
1295 OpStore %58 %56
1296 %62 = OpAccessChain %15 %46 %14
1297 %63 = OpLoad %6 %62
1298 %64 = OpConvertFToU %13 %63
1299 %205 = OpCompositeConstruct %122 %56 %117 %117 %117
1300 %66 = OpIAdd %13 %64 %65
1301 %204 = OpCompositeConstruct %114 %56 %117 %56
1302 %68 = OpAccessChain %67 %61 %14
1303 OpStore %68 %66
1304 OpBranch %43
1305 %69 = OpLabel
1306 %202 = OpCompositeConstruct %44 %32 %32 %10 %11
1307 %209 = OpCompositeConstruct %102 %111 %41
1308 %75 = OpAccessChain %74 %72 %14
1309 OpStore %75 %73
1310 %76 = OpAccessChain %74 %72 %14
1311 %77 = OpLoad %21 %76
1312 %78 = OpLogicalNot %21 %77
1313 %79 = OpAccessChain %74 %72 %18
1314 OpStore %79 %78
1315 %80 = OpAccessChain %74 %72 %14
1316 %81 = OpLoad %21 %80
1317 %82 = OpAccessChain %74 %72 %18
1318 %83 = OpLoad %21 %82
1319 %84 = OpLogicalAnd %21 %81 %83
1320 %85 = OpAccessChain %74 %72 %38
1321 OpStore %85 %84
1322 %89 = OpAccessChain %67 %88 %14
1323 %90 = OpLoad %13 %89
1324 %91 = OpINotEqual %21 %90 %14
1325 %92 = OpAccessChain %74 %72 %65
1326 OpStore %92 %91
1327 OpBranch %43
1328 %43 = OpLabel
1329 %96 = OpLoad %70 %72
1330 %97 = OpCompositeExtract %21 %96 0
1331 %98 = OpCompositeExtract %21 %96 1
1332 %99 = OpCompositeExtract %21 %96 2
1333 %100 = OpCompositeConstruct %93 %97 %98 %99
1334 %200 = OpCompositeConstruct %7 %17 %11
1335 OpStore %95 %100
1336 OpBranch %24
1337 %101 = OpLabel
1338 %105 = OpAccessChain %67 %88 %14
1339 %106 = OpLoad %13 %105
1340 %107 = OpINotEqual %21 %106 %14
1341 %108 = OpCompositeConstruct %102 %107 %107
1342 %210 = OpCompositeConstruct %93 %108 %73
1343 OpStore %104 %108
1344 %211 = OpCompositeConstruct %70 %108 %108
1345 OpBranch %24
1346 %24 = OpLabel
1347 %109 = OpAccessChain %74 %104 %18
1348 %110 = OpLoad %21 %109
1349 %112 = OpLogicalOr %21 %110 %111
1350 %113 = OpAccessChain %74 %104 %14
1351 OpStore %113 %112
1352 %118 = OpAccessChain %57 %116 %14
1353 OpStore %118 %117
1354 %119 = OpAccessChain %57 %116 %14
1355 %120 = OpLoad %50 %119
1356 %121 = OpAccessChain %57 %53 %18
1357 OpStore %121 %120
1358 %125 = OpAccessChain %57 %116 %14
1359 %126 = OpLoad %50 %125
1360 %127 = OpAccessChain %57 %53 %18
1361 %203 = OpCompositeConstruct %51 %126 %120
1362 %128 = OpLoad %50 %127
1363 %129 = OpIAdd %50 %126 %128
1364 %130 = OpAccessChain %57 %124 %65
1365 OpStore %130 %129
1366 %134 = OpAccessChain %57 %116 %14
1367 %135 = OpLoad %50 %134
1368 %136 = OpBitcast %13 %135
1369 %208 = OpCompositeConstruct %131 %14 %18 %136 %136
1370 %137 = OpAccessChain %67 %133 %14
1371 OpStore %137 %136
1372 %207 = OpCompositeConstruct %59 %14 %18 %136
1373 OpReturn
1374 OpFunctionEnd
1375 )";
1376
1377 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1378 }
1379
TEST(TransformationCompositeConstructTest,AddSynonymsForRelevantIds)1380 TEST(TransformationCompositeConstructTest, AddSynonymsForRelevantIds) {
1381 std::string shader = R"(
1382 OpCapability Shader
1383 %1 = OpExtInstImport "GLSL.std.450"
1384 OpMemoryModel Logical GLSL450
1385 OpEntryPoint Fragment %4 "main"
1386 OpExecutionMode %4 OriginUpperLeft
1387 OpSource ESSL 310
1388 %2 = OpTypeVoid
1389 %3 = OpTypeFunction %2
1390 %6 = OpTypeFloat 32
1391 %7 = OpTypeVector %6 3
1392 %8 = OpTypePointer Function %7
1393 %10 = OpConstant %6 1
1394 %11 = OpConstantComposite %7 %10 %10 %10
1395 %17 = OpTypeVector %6 4
1396 %18 = OpTypePointer Function %17
1397 %21 = OpConstant %6 2
1398 %32 = OpTypeMatrix %17 3
1399 %33 = OpTypePointer Private %32
1400 %34 = OpVariable %33 Private
1401 %35 = OpTypeMatrix %7 4
1402 %36 = OpTypePointer Private %35
1403 %37 = OpVariable %36 Private
1404 %38 = OpTypeVector %6 2
1405 %39 = OpTypeInt 32 0
1406 %40 = OpConstant %39 3
1407 %41 = OpTypeArray %38 %40
1408 %42 = OpTypePointer Private %41
1409 %43 = OpVariable %42 Private
1410 %100 = OpUndef %7
1411 %101 = OpUndef %17
1412 %4 = OpFunction %2 None %3
1413 %5 = OpLabel
1414 %9 = OpVariable %8 Function
1415 %12 = OpVariable %8 Function
1416 %14 = OpVariable %8 Function
1417 %19 = OpVariable %18 Function
1418 %26 = OpVariable %18 Function
1419 %29 = OpVariable %18 Function
1420 OpStore %9 %11
1421 %13 = OpLoad %7 %9
1422 OpStore %12 %13
1423 %15 = OpLoad %7 %12
1424 %16 = OpVectorShuffle %7 %15 %15 2 1 0
1425 OpStore %14 %16
1426 %20 = OpLoad %7 %14
1427 %22 = OpCompositeExtract %6 %20 0
1428 %23 = OpCompositeExtract %6 %20 1
1429 %24 = OpCompositeExtract %6 %20 2
1430 %25 = OpCompositeConstruct %17 %22 %23 %24 %21
1431 OpStore %19 %25
1432 %27 = OpLoad %17 %19
1433 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
1434 OpStore %26 %28
1435 %30 = OpLoad %7 %9
1436 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
1437 OpStore %29 %31
1438 OpReturn
1439 OpFunctionEnd
1440 )";
1441
1442 const auto env = SPV_ENV_UNIVERSAL_1_3;
1443 const auto consumer = nullptr;
1444 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1445 spvtools::ValidatorOptions validator_options;
1446 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1447 kConsoleMessageConsumer));
1448 TransformationContext transformation_context(
1449 MakeUnique<FactManager>(context.get()), validator_options);
1450 TransformationCompositeConstruct transformation(
1451 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
1452 ASSERT_TRUE(
1453 transformation.IsApplicable(context.get(), transformation_context));
1454 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1455 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1456 kConsoleMessageConsumer));
1457 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1458 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
1459 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1460 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
1461 }
1462
TEST(TransformationCompositeConstructTest,DontAddSynonymsForIrrelevantIds)1463 TEST(TransformationCompositeConstructTest, DontAddSynonymsForIrrelevantIds) {
1464 std::string shader = R"(
1465 OpCapability Shader
1466 %1 = OpExtInstImport "GLSL.std.450"
1467 OpMemoryModel Logical GLSL450
1468 OpEntryPoint Fragment %4 "main"
1469 OpExecutionMode %4 OriginUpperLeft
1470 OpSource ESSL 310
1471 %2 = OpTypeVoid
1472 %3 = OpTypeFunction %2
1473 %6 = OpTypeFloat 32
1474 %7 = OpTypeVector %6 3
1475 %8 = OpTypePointer Function %7
1476 %10 = OpConstant %6 1
1477 %11 = OpConstantComposite %7 %10 %10 %10
1478 %17 = OpTypeVector %6 4
1479 %18 = OpTypePointer Function %17
1480 %21 = OpConstant %6 2
1481 %32 = OpTypeMatrix %17 3
1482 %33 = OpTypePointer Private %32
1483 %34 = OpVariable %33 Private
1484 %35 = OpTypeMatrix %7 4
1485 %36 = OpTypePointer Private %35
1486 %37 = OpVariable %36 Private
1487 %38 = OpTypeVector %6 2
1488 %39 = OpTypeInt 32 0
1489 %40 = OpConstant %39 3
1490 %41 = OpTypeArray %38 %40
1491 %42 = OpTypePointer Private %41
1492 %43 = OpVariable %42 Private
1493 %100 = OpUndef %7
1494 %101 = OpUndef %17
1495 %4 = OpFunction %2 None %3
1496 %5 = OpLabel
1497 %9 = OpVariable %8 Function
1498 %12 = OpVariable %8 Function
1499 %14 = OpVariable %8 Function
1500 %19 = OpVariable %18 Function
1501 %26 = OpVariable %18 Function
1502 %29 = OpVariable %18 Function
1503 OpStore %9 %11
1504 %13 = OpLoad %7 %9
1505 OpStore %12 %13
1506 %15 = OpLoad %7 %12
1507 %16 = OpVectorShuffle %7 %15 %15 2 1 0
1508 OpStore %14 %16
1509 %20 = OpLoad %7 %14
1510 %22 = OpCompositeExtract %6 %20 0
1511 %23 = OpCompositeExtract %6 %20 1
1512 %24 = OpCompositeExtract %6 %20 2
1513 %25 = OpCompositeConstruct %17 %22 %23 %24 %21
1514 OpStore %19 %25
1515 %27 = OpLoad %17 %19
1516 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
1517 OpStore %26 %28
1518 %30 = OpLoad %7 %9
1519 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
1520 OpStore %29 %31
1521 OpReturn
1522 OpFunctionEnd
1523 )";
1524
1525 const auto env = SPV_ENV_UNIVERSAL_1_3;
1526 const auto consumer = nullptr;
1527 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1528 spvtools::ValidatorOptions validator_options;
1529 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1530 kConsoleMessageConsumer));
1531 TransformationContext transformation_context(
1532 MakeUnique<FactManager>(context.get()), validator_options);
1533 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(25);
1534
1535 TransformationCompositeConstruct transformation(
1536 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
1537 ASSERT_TRUE(
1538 transformation.IsApplicable(context.get(), transformation_context));
1539 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1540 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1541 kConsoleMessageConsumer));
1542 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1543 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
1544 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1545 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
1546 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1547 MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2})));
1548 }
1549
TEST(TransformationCompositeConstructTest,DontAddSynonymsInDeadBlock)1550 TEST(TransformationCompositeConstructTest, DontAddSynonymsInDeadBlock) {
1551 std::string shader = R"(
1552 OpCapability Shader
1553 %1 = OpExtInstImport "GLSL.std.450"
1554 OpMemoryModel Logical GLSL450
1555 OpEntryPoint Fragment %4 "main"
1556 OpExecutionMode %4 OriginUpperLeft
1557 OpSource ESSL 320
1558 %2 = OpTypeVoid
1559 %3 = OpTypeFunction %2
1560 %6 = OpTypeInt 32 1
1561 %7 = OpTypeVector %6 2
1562 %8 = OpTypePointer Function %7
1563 %10 = OpConstant %6 0
1564 %11 = OpConstant %6 1
1565 %12 = OpConstantComposite %7 %10 %11
1566 %13 = OpTypeBool
1567 %14 = OpConstantFalse %13
1568 %4 = OpFunction %2 None %3
1569 %5 = OpLabel
1570 %9 = OpVariable %8 Function
1571 OpStore %9 %12
1572 OpSelectionMerge %16 None
1573 OpBranchConditional %14 %15 %16
1574 %15 = OpLabel
1575 OpBranch %16
1576 %16 = OpLabel
1577 OpReturn
1578 OpFunctionEnd
1579 )";
1580
1581 const auto env = SPV_ENV_UNIVERSAL_1_3;
1582 const auto consumer = nullptr;
1583 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1584 spvtools::ValidatorOptions validator_options;
1585 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1586 kConsoleMessageConsumer));
1587 TransformationContext transformation_context(
1588 MakeUnique<FactManager>(context.get()), validator_options);
1589 transformation_context.GetFactManager()->AddFactBlockIsDead(15);
1590
1591 TransformationCompositeConstruct transformation(
1592 7, {10, 11}, MakeInstructionDescriptor(15, SpvOpBranch, 0), 100);
1593 ASSERT_TRUE(
1594 transformation.IsApplicable(context.get(), transformation_context));
1595 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1596 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1597 MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {})));
1598 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1599 MakeDataDescriptor(100, {1}), MakeDataDescriptor(11, {})));
1600 }
1601
TEST(TransformationCompositeConstructTest,OneIrrelevantComponent)1602 TEST(TransformationCompositeConstructTest, OneIrrelevantComponent) {
1603 std::string shader = R"(
1604 OpCapability Shader
1605 %1 = OpExtInstImport "GLSL.std.450"
1606 OpMemoryModel Logical GLSL450
1607 OpEntryPoint Fragment %4 "main"
1608 OpExecutionMode %4 OriginUpperLeft
1609 OpSource ESSL 320
1610 %2 = OpTypeVoid
1611 %3 = OpTypeFunction %2
1612 %6 = OpTypeInt 32 1
1613 %7 = OpTypeStruct %6 %6 %6
1614 %8 = OpConstant %6 42
1615 %9 = OpConstant %6 50
1616 %10 = OpConstant %6 51
1617 %4 = OpFunction %2 None %3
1618 %5 = OpLabel
1619 OpReturn
1620 OpFunctionEnd
1621 )";
1622
1623 const auto env = SPV_ENV_UNIVERSAL_1_3;
1624 const auto consumer = nullptr;
1625 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1626 spvtools::ValidatorOptions validator_options;
1627 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1628 kConsoleMessageConsumer));
1629 TransformationContext transformation_context(
1630 MakeUnique<FactManager>(context.get()), validator_options);
1631 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(8);
1632
1633 TransformationCompositeConstruct transformation(
1634 7, {8, 9, 10}, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
1635 ASSERT_TRUE(
1636 transformation.IsApplicable(context.get(), transformation_context));
1637 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1638 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1639 MakeDataDescriptor(100, {0}), MakeDataDescriptor(8, {})));
1640 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1641 MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {})));
1642 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1643 MakeDataDescriptor(100, {2}), MakeDataDescriptor(10, {})));
1644 }
1645
TEST(TransformationCompositeConstructTest,IrrelevantVec2ThenFloat)1646 TEST(TransformationCompositeConstructTest, IrrelevantVec2ThenFloat) {
1647 std::string shader = R"(
1648 OpCapability Shader
1649 %1 = OpExtInstImport "GLSL.std.450"
1650 OpMemoryModel Logical GLSL450
1651 OpEntryPoint Fragment %4 "main"
1652 OpExecutionMode %4 OriginUpperLeft
1653 OpSource ESSL 320
1654 %2 = OpTypeVoid
1655 %3 = OpTypeFunction %2
1656 %6 = OpTypeFloat 32
1657 %7 = OpTypeVector %6 2
1658 %8 = OpTypeVector %6 3
1659 %9 = OpConstant %6 0
1660 %11 = OpConstant %6 1
1661 %12 = OpConstant %6 2
1662 %10 = OpConstantComposite %7 %11 %12
1663 %4 = OpFunction %2 None %3
1664 %5 = OpLabel
1665 OpReturn
1666 OpFunctionEnd
1667 )";
1668
1669 const auto env = SPV_ENV_UNIVERSAL_1_3;
1670 const auto consumer = nullptr;
1671 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1672 spvtools::ValidatorOptions validator_options;
1673 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1674 kConsoleMessageConsumer));
1675 TransformationContext transformation_context(
1676 MakeUnique<FactManager>(context.get()), validator_options);
1677
1678 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10);
1679
1680 TransformationCompositeConstruct transformation(
1681 8, {10, 9}, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
1682 ASSERT_TRUE(
1683 transformation.IsApplicable(context.get(), transformation_context));
1684 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1685 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1686 MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {0})));
1687 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1688 MakeDataDescriptor(100, {1}), MakeDataDescriptor(10, {1})));
1689 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1690 MakeDataDescriptor(100, {2}), MakeDataDescriptor(9, {})));
1691 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1692 MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {})));
1693 }
1694
1695 } // namespace
1696 } // namespace fuzz
1697 } // namespace spvtools
1698