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