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