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